//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<thread.h>
///	@path	~/lib/system/
///	@date	2007/09/10
///	@desc	Thread pool.

#pragma once

#include "xeres.h"

#include "lib/system/thread.h"
#include "lib/system/lock.h"
#include "lib/system/signal.h"
#include "lib/utilities/callback.h"

#include <list>
#include <vector>

namespace xeres {

	/*!
		\class	ThreadPool
		\brief	Thread pool is a set of threads. It dispatch several jobs to
				different threads in order to make them work parallel.
	*/
	class ThreadPool
	{
	protected:

		/// \name Constructor & Destructor
		//@{

		/// \ctor
		ThreadPool( void );

		/// \dtor
		~ThreadPool( void );

		//@}

		/// \name Internal Manipulations
		//@{

		/*!
			\brief		Initialize the thread pool.
		*/
		void Initialize( int count , bool lower_priority , const std::vector<bool> * processors );

		/*!
			\brief		Stop all threads, empty jobs.
		*/
		void Finalize( void );

		/*!
			\brief		Determine if thread pool is initialized.
		*/
		bool IsInitialized( void ) const { return m_inited; }

		//@}

	private:

		// forward declaration
		class _JobThread;

	public:

		/*!
			\class	Job
			\brief	Interface of a job in thread pool.
		*/
		class Job
		{
		public:

			/// \ctor
			Job( bool self_destruct );

			/// \dtor
			virtual ~Job( void );

			/*!
				\brief		Determine if job is self destruct.
							The thread pool will not delete it after execution.
			*/
			bool IsSelfDestruct( void ) const { return m_selfDestruct; }

			/*!
				\brief		Query if job is completed.
			*/
			bool IsCompleted( void ) const { return m_completed; }

		//@ interface
			
			/*!
				\brief		Execute job. Called when job Starts.
			*/
			virtual void Execute( void ) = 0;

			/*!
				\brief		Job done callback.
			*/
			virtual void Done( void );

			/*!
				\brief		Call when job canceled.
			*/
			virtual void Canceled( void );

		private:

			/*! 
				\breief		Run jobs correctly.
			*/
			static void RunMe( Job * job );

			friend class ThreadPool;
			friend class ThreadPool::_JobThread;

		//@ data
			// self destruct tag
			bool	m_selfDestruct;
			// job complete tag
			bool	m_completed;

			bool	m_spare[2];
		};

		/// \name Manipulation Interfaces
		//@{

		/*!
			\brief		Get free thread count.
		*/
		int Free( void ) const { return m_free; }

		/*!
			\brief		Add new job to threads.
		*/
		void AddJob( Job * job );

		/*!
			\brief		Initialize caller's thread.
		*/
		void InitializeThisThread( const char * name );

		/*!
			\brief		Finalize caller's thread.
		*/
		void FinalizeThisThread( void );

		/*! 
			\brief		Get initialized.
		*/
		bool IsInitialized( void ) { return m_inited; }

		/*! 
			\brief		Use current thread to take jobs and execute.
		*/
		bool JoinAndTakeJob( void );

		/*! 
			\brief		Wait for all jobs completed.
		*/
		void WaitJobsComplete( void );

		//@}

	private:

		/// \name Internal Implementation
		//@{

		/*!
			\class	_JobThread
			\brief	Encapsulate a job thread, which execute jobs
					in the thread pool queue.
		*/
		class _JobThread : public Thread
		{
		public:

			/// \ctor
			_JobThread( ThreadPool * pool , char id );

			/// \dtor
			virtual ~_JobThread( void );

			/*!
				\brief		Execution of a thread.
				\return		Thread exit code.
			*/
			virtual uint32 Execute( void );

			/*!
				\brief		Schedule new job in.
				\param[in]	job			Job instance.
			*/
			void ScheduleJob( Job * job );

			/*!
				\brief		Stop current job thread.
			*/
			void StopThread( void );

			/*!
				\brief		Get thread handle.
				\return		Current thread handle.
			*/
			uintptr_t Handle( void ) const { return Thread::Handle(); }

			/*!
				\brief		Get job thread id.
			*/
			int GetId( void ) const { return m_id; }

			/*! 
				\brief		Determine if thread is idle.
			*/
			bool IsIdle( void ) const { return m_working == 0; }

		private:

			friend class ThreadPool;

			// tags
			bool					m_running;
			bool					m_spare[2];

			// thread id
			char					m_id;

			// working tag
			volatile int			m_working;

			// the pool
			ThreadPool *			m_pool;

			Job *					m_next;

			// task lock			
			ThreadLock				m_lock;

			// task signal
			Signal					m_signal;

			// thread name
			DEBUG_RUN( AString		m_threadName );

		};

		friend class _JobThread;

		/*!
			\brief		Notify the pool that this thread is empty.
			\param[in]	thread	The empty job thread.
		*/
		void NotifyEmpty( _JobThread * thread );

		/*!
			\brief		Notify the pool that this thread is awake.
			\param[in]	thread	The awake job thread.
		*/
		void NotifyAwake( _JobThread * thread );

		/*!	
			\brief		Fetch job from job list.
		*/
		bool FetchJob( Job *& job );

		//@}

		/// \name Data
		//@{

		// normal thread scheduling lock
		ThreadLock						m_scheduleLock;

		// free thread counter
		volatile int					m_free;

		// thread counter
		volatile int					m_counter;

		// total job count
		volatile int					m_jobs;

		// status
		bool							m_inited;
		bool							m_spare0[3];

		// thread local storages		
		uint32							m_tlsThreadInit;

		// most recently slept normal thread
		volatile _JobThread *			m_sleepThread;

		// job threads
		std::vector< _JobThread * >		m_threads;

		// schedule list
		std::list< Job * >				m_jobList;

		//@}
	};

} // namespace
